package parsing.productions;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import world.Critter;


public class Command extends AbstractNode implements ExecutableNode {
	//invariant for children: contains at least one child, in the form Update* (Update | Action)
	
	/**
	 * Creates a new Command
	 * @param allChildren list of this Command's children
	 * Requires: allChildren's contents are in the form Update* (Update | Action)
	 */
	public Command(List<AbstractNode> allChildren){
		if(allChildren.size() > 0)
			children= allChildren;
		else
			throw new IllegalArgumentException("There must be at least one child to make this production.");
	}

	/**
	 * Returns toMutate with one mutation. 
	 * Effects: makes the mutation directly to toMutate
	 * @param toMutate the program to make the change to
	 * @return the mutated version of toMutate
	 * Requires: toMutate is a Command
	 */
	public static AbstractNode mutate(AbstractNode toMutate, Program genome){
		LinkedList<MutableNode> mutableChildren = new LinkedList<MutableNode>();
		LinkedList<MutableNode> descendants = new LinkedList<MutableNode>();
		for(Node n : toMutate.children)
			mutableChildren.add((MutableNode) n);
		for(MutableNode n : mutableChildren)
			n.addMutableTree(descendants);
		Random rnd = new Random();
		if(descendants.size() != 0){//this will almost certainly never be 0
			int nodeToMutate = rnd.nextInt(descendants.size());//choose the node to mutate out of all of toMutate's descendants
			descendants.get(nodeToMutate).mutate(genome);
		}
		return toMutate;
	}
	
	@Override
	public void prettyPrint(StringBuffer sb) {
		for(Node n : children){
			sb.append("\n");
			n.prettyPrint(sb);
		}
	}

	@Override
	public Node duplicate() {
		List<AbstractNode> duplicateChildren= new LinkedList<AbstractNode>();
		for (AbstractNode n : children) {
			duplicateChildren.add((AbstractNode)n.duplicate());
		}
		return new Command(duplicateChildren);
	}

	@Override
	public boolean execute(Critter c) {
		for(Node n: children)
			((ExecutableNode) n).execute(c);
		return true;
	}

}
